#!/usr/bin/env /devel/ringojs/bin/ringo

// Copyright 2012 Jay Young. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview
 *
 * A tool designed to document code written in the style of the Closure Library
 * using Closure-style type annotations.
 *
 * Main program sequence starts here.
 *
 * The whole program consists of the following high-level outline:
 *
 * 1. Parse input files into an AST.  Each input will be represented by a
 *      single <SCRIPT> node in the AST. (rdoc/parser/Parser)
 * 2.
 *  a. For each input, document everything in that input file and output the
 *      resulting JSON structure to a DocInfo file.  There is a 1:1 mapping
 *      between inputs and DocInfos, but any input file with @nocompile
 *      will be skipped. (rdoc/documentor/Documentor)
 *  b. During 2a, each type (classes, interfaces, enums, typedefs) is entered
 *      as a key in the singleton DocMap object for the program's run.  The
 *      value is a record containing the type's type, its source input file,
 *      and base class, and extended/implemented interfaces.  Later phases of
 *      the program iterate through the DocMap entries and operate
 *      on some or all of these types.
 * 3. Iterate through all classes and interfaces in the DocMap, find all
 *      class methods with "@override", find the overridden method in the
 *      super-type tree and pull the missing docs into the overriding class.
 * 4. Write out HTML doc files for all types in the DocMap and an index.
 *
 * This process can be stopped or stared in the middle if certain command-line
 * flags are present:
 *
 * -a/--ast:  Parse the input files and print the AST
 *      to stdout.
 * -p/--parse: Parse the input files, generate the DocInfo files/DocMap file
 *      and quit.
 * -g/--generate: Skip re-parsing and processing the inputs.  Instead, use
 *      existing DocInfo/DocMap files to generate the final HTML documentation.
 * -f/--force:  When performing a full program run, the default behavior
 *      compares the last-modified time of the source file to that of any
 *      existing DocInfo file.  If the DocInfo file is newer than the latest
 *      changes to the source file, it uses the pre-built DocInfo instead of
 *      re-parsing the input.  This flag disables that behavior and always
 *      re-parses the input file.
 *
 *
 * @author jayyoung9909@gmail.com (Jay Young)
 */


// These classpath additions are required when running from source, but cannot
// be executed when running from the RDoc JAR file.
if (! /\.jar\/rdoc\.js$/.test(module.path) ) {
  addToClasspath('.');
  addToClasspath('lib/compiler.jar');
}


var argParser = require('ringo/args').Parser,
    args = new argParser(),
    logger = require('ringo/logging').getLogger('RDoc'),
    {ConfigParser} = require('rdoc/config');

args.addOption('h', 'help', null, 'Prints this usage text')
    .addOption('a', 'ast', null, 'Print the AST and quit')
    .addOption('f', 'force', null, 'Re-parse regardless of last-modified check')
    .addOption('p', 'parse', null, 'Parse the inputs and generate the ' +
               'intermediate data but do not build the doc files')
    .addOption('g', 'generate', null, 'Generate the final doc files from ' +
               'existing intermediate data in the output path.')
    .addOption('c', 'config', 'config', 'Path to a config.json file.  ' +
               'Required.')
    .addOption('v', 'verbose', null, 'Print lots of logging information')
    .addOption('t', 'test', 'name', 'Run the tests in the named test case.  ' +
               'Pass "all" to run all tests.');


// Parse command-line options
var defaults = {},
    options = args.parse(Array.prototype.slice.call(arguments, 1), defaults);

var config = new ConfigParser(options, args);

// If "-t <test_case|all>" was passed, run one or all unit tests and exit
if (config.test) {
  system.exit(require('test').run(require('rdoc/tests/' + config.test)));
}


// A single DocMap object is populated somehow at the start and is used
// throughout the entire program run.
var docMap;

// This first phase is all about generating the DocMap instance to used to
// write the HTML docs.
if (! config.usePrebuilt) {
  // If "-g/--generate" was NOT passed on the command-line, get the set of
  // input files and prep a Parser.
  var fileset = config.getFileset(),
      {Parser} = require('rdoc/parser'),
      parser = new Parser(config.verbose);

  // If "-a/--ast" was passed, print the AST and quit.
  if (config.ast) {
    parser.printAST(fileset);
    system.exit(0);
  }

  // Else, parse the input.  This gives us an array of <SCRIPT> AST nodes and
  // a reference to the compiler's TypeRegistry object, which is required for
  // resolving JsTypeExpression objects.
  var {scripts, typeRegistry} = parser.parse(fileset),
      {Documentor} = require('rdoc/documentor'),
      documentor = new Documentor(typeRegistry, config);

  // Prep a Documentor instance and pass the <SCRIPT> nodes through it to
  // produce the DocMap object.
  docMap =
      documentor.buildVisitorChain().documentScripts(scripts, config.verbose);

  // Null out references to reduce memory.  These things are no longer needed,
  // and the following processes are very memory intensive.
  scripts = typeRegistry = parser = documentor = null;

  // Search for and process @override annotations.
  var {Overrides} = require('rdoc/overrides'),
      overrides = new Overrides(docMap, config);

  overrides.processAll();
}
else {
  // If "-g/--generate" WAS passed on the command-line, find the existing
  // serialized DocMap file, parse it, and use that going forward.
  if (! config.parse) {
    docMap = config.parsePrebuilt();
  }
}

// This phase is all about writing out the HTML docs.  At this point, we don't
// care where the DocMap came from.
if (! config.parse) {
  var DocWriter = require('rdoc/docwriter').DocWriter,
      docWriter = new DocWriter(docMap, config);
  
  docWriter.write();
}
